package ffprobe

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/util/gconv"
	"log"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

// EncFormat 视频封装格式
func (p *SFFProbe) EncFormat() (interface{}, error) {
	// 获取解析的视频内容
	if err := p.Parse(); err != nil {
		return nil, err
	}
	format, ok := p.parse[`format`]
	if !ok {
		return nil, errors.New(`视频封装格式内容不存在`)
	}
	return format, nil
}

// Format 视频封装格式内容格式化
func (p *SFFProbe) Format() (*Format, error) {
	raw, err := p.EncFormat()
	if err != nil {
		return nil, err
	}
	format := &Format{}
	if err = gconv.Scan(raw, &format); err != nil {
		return nil, err
	}
	return format, nil
}

// MustFormat 视频封装格式内容格式化
func (p *SFFProbe) MustFormat() *Format {
	item, err := p.Format()
	if err != nil {
		log.Fatalln(err)
	}
	return item
}

// Size 视频大小
func (p *SFFProbe) Size() int {
	if item := p.MustFormat(); item != nil {
		return item.Size
	}
	return 0
}

// FmtSizeToString 将文件大小格式化为带有指定单位和精度的字符串
func (p *SFFProbe) FmtSizeToString(t string, decimal int) string {
	size := p.Size()
	if size == 0 {
		return ``
	}
	// 转换为字符串
	return p.SizeToString(t, decimal, size)
}

// Duration 视频时长
func (p *SFFProbe) Duration() float64 {
	if item := p.MustFormat(); item != nil {
		return item.Duration
	}
	return 0
}

// Filename 获取视频名
func (p *SFFProbe) Filename() string {
	if item := p.MustFormat(); item != nil {
		return item.Filename
	}
	return ``
}

// Ext 获取视频文件后缀
func (p *SFFProbe) Ext() string {
	if filename := p.Filename(); filename != `` {
		fs := strings.Split(filename, `.`)
		return fs[len(fs)-1]
	}
	return ``
}

// M3u8Size 获取视频m3u8格式大小
func (p *SFFProbe) M3u8Size() (int, error) {
	total := p.Size() // 获取M3u8主文件的大小
	// 打开文件
	fs, err := os.Open(p.src)
	if err != nil {
		return 0, fmt.Errorf(`打开%s文件失败%w`, p.src, err)
	}
	defer func() {
		_ = fs.Close()
	}()

	// 编译正则表达式，匹配#EXTINF行后的文件名
	// 假设文件名紧跟在逗号和至少一个空格之后，直到行尾或遇到#字符
	re := regexp.MustCompile(`\s*([^\s#]+.ts)`)
	// 逐行读取文件
	scanner := bufio.NewScanner(fs)
	for scanner.Scan() {
		line := scanner.Text()

		// 使用正则表达式查找匹配项
		matches := re.FindStringSubmatch(line)
		if len(matches) < 1 {
			continue
		}
		// matches[0] 包含我们感兴趣的文件名
		tsUrl := filepath.Dir(p.src) + `\` + strings.TrimSpace(matches[0])
		stat, err := os.Stat(tsUrl)
		if err != nil {
			log.Fatalln(`读取TS文件失败`, tsUrl, err)
		}
		total += int(stat.Size())
	}

	// 逐行扫描是否出错
	if err = scanner.Err(); err != nil {
		fmt.Println("Error reading file:", err)
		return 0, err
	}
	return total, nil
}

// SizeToString 视频内存大小转换为字符串
func (p *SFFProbe) SizeToString(t string, decimal, size int) string {
	// 设置计算单位
	unitsMap := map[string]float64{
		`KB`: 1024,
		`M`:  1024 * 1024,
		`GB`: 1024 * 1024 * 1024,
		`TB`: 1024 * 1024 * 1024 * 1024,
	}
	// 转大写，避免入参单位是小写
	t = strings.ToUpper(t)
	u, ok := unitsMap[t]
	if !ok {
		// 默认返回字节
		return strconv.Itoa(size) + `B`
	}

	// 保留小数点，注：避免小数点小于等于0，计算错误
	var d float64 = 1
	if decimal > 1 {
		d = math.Pow(10, float64(decimal)) // 10的N次方
	}
	value := math.Round(float64(size)/u*d) / d

	// 转换为字符串
	return strconv.FormatFloat(value, 'f', decimal, 64) + t
}
